<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 流年 <liu21st@gmail.com>
// +----------------------------------------------------------------------

// 应用公共文件
use app\http\exception\BusinessException;
use randy\MyRedis;
use randy\RedisLock;
use think\Config;
use think\facade\Request;

// 系统默认权限
const AUTH_SUPER_ADMINISTRATOR = 1;
const AUTH_ADMINISTRATOR = 2;
const AUTH_CLIENT = 3;
const AUTH_GUEST = 2;
const APP = 'APP';
const ADMIN = 'ADMIN';

error_reporting(0);

define('G_HTTP', isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == '443' ? "https://" : "http://");
define('G_HTTP_HOST', $_SERVER['HTTP_HOST'] ?? "");
defined('PUBLIC_PATH') or define('PUBLIC_PATH', dirname(G_HTTP . G_HTTP_HOST . $_SERVER['SCRIPT_NAME']));

/**
 * 调试输出
 *
 * @param unknown $data
 */
function print_data($data, $var_dump = false)
{
    header("Content-type: text/html; charset=utf-8");
    echo "<pre>";
    if ($var_dump) {
        var_dump($data);
    } else {
        print_r($data);
    }
    exit();
}

function objToArray($data)
{
    return json_decode(json_encode($data), true);
}

function curlSend($url)
{
    try {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $res = curl_exec($ch);
        curl_close($ch);
        return $res;
    } catch (\Exception $e) {
        return null;
    }
}

if (!function_exists('auto_hid_substr')) {
    /**
     * 智能字符串模糊化
     *
     * @param string $str 被模糊的字符串
     * @param int    $len 模糊的长度
     *
     * @return string
     */
    function auto_hid_substr(string $str, $len = 3)
    {
        if (empty($str)) {
            return null;
        }

        $sub_str = mb_substr($str, 0, 1, 'utf-8');
        for ($i = 0; $i < $len; $i++) {
            $sub_str .= '*';
        }

        if (mb_strlen($str, 'utf-8') <= 2) {
            $str = $sub_str;
        }

        $sub_str .= mb_substr($str, -1, 1, 'utf-8');
        return $sub_str;
    }
}

/**
 * 获取图片的Base64编码(不支持url)
 *
 * @param string $img_file 传入本地图片地址
 *
 * @return string
 */
function imgToBase64($img_file)
{
    $img_base64 = '';
    if (file_exists($img_file)) {
        $app_img_file = $img_file;               // 图片路径
        $img_info = getimagesize($app_img_file); // 取得图片的大小，类型等

        //echo '<pre>' . print_r($img_info, true) . '</pre><br>';
        $fp = fopen($app_img_file, "r");         // 图片是否可读权限

        if ($fp) {
            $filesize = filesize($app_img_file);
            $content = fread($fp, $filesize);
            $file_content = chunk_split(base64_encode($content)); // base64编码
            switch ($img_info[2]) {           //判读图片类型
                case 1:
                    $img_type = "gif";
                    break;
                case 2:
                    $img_type = "jpg";
                    break;
                case 3:
                    $img_type = "png";
                    break;
            }

            $img_base64 = 'data:image/' . $img_type . ';base64,' . $file_content;//合成图片的base64编码

        }
        fclose($fp);
    }

    return $img_base64; //返回图片的base64
}

function to_last_month($num, $today)
{
    $arr = [];
    $m = '-' . $num . ' month';
    $old_time = strtotime($m, strtotime($today));
    for ($i = 0; $i <= $num - 1; ++$i) {
        $t = strtotime("+$i month", $old_time);
        $arr[] = date('Y-m', $t);
    }
    //return $str = "'".str_replace( ",","','", implode(',',$arr))."'";
    return $arr;
}

function getDateNum()
{
    $str = date("Ymdhis", time()) . getNumber(8);
    return $str;
}

function getDateFromRange($startdate, $enddate)
{
    $stimestamp = strtotime($startdate);
    $etimestamp = strtotime($enddate);

    // 计算日期段内有多少天
    $days = ($etimestamp - $stimestamp) / 86400 + 1;

    // 保存每天日期
    $date = [];

    for ($i = 0; $i < $days; $i++) {
        $date[] = date('Y-m-d', $stimestamp + (86400 * $i));
    }

    return $date;
}

/**
 * @param $date 2019-12-11
 *
 * @return string
 * 获取指定日期是星期几
 */
function getWeek($date)
{
    $weekarray = ["日", "一", "二", "三", "四", "五", "六"];
    $str = "星期" . $weekarray[date("w", strtotime($date))];

    return $str;
}

/**
 * @param $date 2019-12-11
 *
 * @return string
 * 获取指定日期是几号数字
 */
function getWeekNum($date)
{
    $weekarray = ["7", "1", "2", "3", "4", "5", "6"];
    $str = $weekarray[date("w", strtotime($date))];

    return $str;
}

function showMonthRange($start, $end)
{
    $end = date('Y-m', strtotime($end)); // 转换为月
    $range = [];
    $i = 0;
    do {
        $month = date('Y-m', strtotime($start . ' + ' . $i . ' month'));
        //echo $i . ':' . $month . '<br>';
        $range[] = $month;
        $i++;
    } while ($month < $end);

    return $range;
}


function now_time($time = 0)
{
    return $time ? date("Y-m-d H:i:s", $time) : date('Y-m-d H:i:s');
}

function begin_time()
{
    $data = date("Y-m-d H:i:s", 946659661);
    return $data;
}

/**
 * @param $Obj
 * @param $key
 *
 * @return string
 */
function getSign($Obj, $key)
{
    //    var_dump($Obj);//die;
    foreach ($Obj as $k => $v) {
        $Parameters[$k] = $v;
    }
    //签名步骤一：按字典序排序参数
    ksort($Parameters);
    $String = formatBizQueryParaMap($Parameters, false);
    //echo '【string1】'.$String.'</br>';
    //签名步骤二：在string后加入KEY
    $String = $String . "&key=" . $key;
    //echo "【string2】".$String."</br>";
    //签名步骤三：MD5加密
    $String = md5($String);
    //echo "【string3】 ".$String."</br>";
    //签名步骤四：所有字符转为大写
    $result_ = strtoupper($String);
    //echo "【result】 ".$result_."</br>";
    return $result_;
}

/**
 * @param $length
 *
 * @return string|null
 */
function getRandChar($length)
{
    $str = null;
    $strPol = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ";
    $max = strlen($strPol) - 1;

    for ($i = 0; $i < $length; $i++) {
        $str = $str . $strPol[rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
    }

    return $str;
}

/**
 * @param $length
 *
 * @return string|null
 */
function sqlGetRandChar($length)
{
    $str = null;
    $strPol = "0123456789ABCDEF";
    $max = strlen($strPol) - 1;

    for ($i = 0; $i < $length; $i++) {
        $str = $str . $strPol[rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
    }

    return $str;
}

//获取当月日期
function get_day($date)
{
    $j = date("t", strtotime($date));                          //获取当前月份天数
    $start_time = strtotime(date('Y-m-01', strtotime($date))); //获取本月第一天时间戳
    $array = [];
    for ($i = 0; $i < $j; $i++) {
        $array[] = date('Y-m-d', $start_time + $i * 86400); //每隔一天赋值给数组
    }
    return $array;
}

function get_month($year)
{
    for ($i = 1; $i <= 12; $i++) {
        if ($i < 10) {
            $array[] = $year . "-0" . $i;
        } else {
            $array[] = $year . "-" . $i;
        }
    }
    return $array;
}

/**
 * @param $length
 *
 * @return string|null
 */
function getNumber($length)
{
    $str = null;
    $strPol = "0123456789";
    $max = strlen($strPol) - 1;

    for ($i = 0; $i < $length; $i++) {
        $str = $str . $strPol[rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
    }

    return $str;
}

function getOrderNumber()
{
    $str = date('YmdHis') . rand(100, 999);
    return $str;
}

/**
 * @param $length
 *
 * @return string|null
 */
function getNumberOne($length)
{
    $str = null;
    $strPol = "123456789";
    $max = strlen($strPol) - 1;

    for ($i = 0; $i < $length; $i++) {
        $str = $str . $strPol[rand(0, $max)]; // rand($min,$max)生成介于min和max两个数之间的一个随机整数
    }

    return $str;
}

/**
 * @param $paraMap
 * @param $urlencode
 *
 * @return bool|string
 */
function formatBizQueryParaMap($paraMap, $urlencode)
{
    //    var_dump($paraMap);//die;
    $buff = "";
    ksort($paraMap);
    foreach ($paraMap as $k => $v) {
        if ($urlencode) {
            $v = urlencode($v);
        }
        //$buff .= strtolower($k) . "=" . $v . "&";
        $buff .= $k . "=" . $v . "&";
    }

    if (strlen($buff) > 0) {
        $reqPar = substr($buff, 0, strlen($buff) - 1);
    }
    //    var_dump($reqPar);//die;
    return $reqPar;
}

/**
 * @param int $len
 *
 * @return bool|string
 */
function randString($len = 4)
{
    $chars = str_repeat('0123456789', $len);
    $chars = str_shuffle($chars);
    $str = substr($chars, 0, $len);
    return $str;
}


/**
 * @param $lat1
 * @param $lng1
 * @param $lat2
 * @param $lng2
 *
 * @return float
 */
function getDistance($lat1, $lng1, $lat2, $lng2)
{
    $earthRadius = 6367000; //approximate radius of earth in meters
    $lat1 = ($lat1 * pi()) / 180;
    $lng1 = ($lng1 * pi()) / 180;
    $lat2 = ($lat2 * pi()) / 180;
    $lng2 = ($lng2 * pi()) / 180;
    $calcLongitude = $lng2 - $lng1;
    $calcLatitude = $lat2 - $lat1;
    $stepOne = pow(sin($calcLatitude / 2), 2) + cos($lat1) * cos($lat2) * pow(sin($calcLongitude / 2), 2);
    $stepTwo = 2 * asin(min(1, sqrt($stepOne)));
    $calculatedDistance = $earthRadius * $stepTwo;
    return round($calculatedDistance);
}

/**
 * @param     $arrays
 * @param     $sort_key
 * @param int $sort_order
 * @param int $sort_type
 *
 * @return array|bool
 */
function my_sort($arrays, $sort_key, $sort_order = SORT_ASC, $sort_type = SORT_NUMERIC)
{
    //数组排序
    if (is_array($arrays)) {
        foreach ($arrays as $array) {
            if (is_array($array)) {
                $key_arrays[] = $array[$sort_key];
            } else {
                return false;
            }
        }
    } else {
        return false;
    }
    array_multisort($key_arrays, $sort_order, $sort_type, $arrays);
    return $arrays;
}

function xml_to_array($xml)
{
    $array = (array)(simplexml_load_string($xml));
    foreach ($array as $key => $item) {
        $array[$key] = struct_to_array((array)$item);
    }
    return $array;
}

function struct_to_array($item)
{
    if (!is_string($item)) {
        $item = (array)$item;
        foreach ($item as $key => $val) {
            $item[$key] = struct_to_array($val);
        }
    }
}

/**
 * @param $origin
 * @param $destination
 * @ 计算两地距离
 *
 * @return bool|string
 */
function distance($origin, $destination)
{
    $url = "http://restapi.amap.com/v3/distance?key=e1729d87fb5cfd4213f3d0ebc3342c03&origins=$origin&destination=$destination";
    //    var_dump($url);die;
    $result = curl_send($url);
    //    $json=json_decode($result);
    return $result;
}

/**
 * @param $origin
 * @param $destination
 *
 * @return bool|string
 */
function latitude_longitude($origin, $destination)
{
    //经纬度
    $address = $origin . "|" . $destination;
    //    var_dump($address);die;
    $url = "http://restapi.amap.com/v3/geocode/geo?key=e1729d87fb5cfd4213f3d0ebc3342c03&address=$address&batch=true";
    $result = curl_send($url);
    //        var_dump($result);die;
    $json = json_decode($result);
    if (empty($json->infocode)) {
        return false;
    }
    //        var_dump($json);die;
    //        var_dump($json);die;
    if ($json->infocode == "10000") {
        //            var_dump($json);die;
        return $json->geocodes[0]->location . "|" . $json->geocodes[1]->location;
    } else {
        return false;
    }
}

function secToTime($times)
{
    $result = '00:00:00';

    $hour = floor($times / 3600);
    $minute = floor(($times - 3600 * $hour) / 60);
    $second = floor((($times - 3600 * $hour) - 60 * $minute) % 60);
    $result = $hour . ':' . $minute . ':' . $second;

    return $result;
}

/**
 * 账户密码加密
 *
 * @param string $str password
 *
 * @return string(32)
 */
function md6($str)
{
    $key = 'account_nobody';
    return md5(md5($str) . $key);
}

function mutime()
{
    $mtimestamp = sprintf("%.3f", microtime(true)); // 带毫秒的时间戳

    $timestamp = floor($mtimestamp);                          // 时间戳
    $milliseconds = round(($mtimestamp - $timestamp) * 1000); // 毫秒

    return $datetime = date("Y-m-d H:i:s", $timestamp) . '.' . $milliseconds;
}

function get_token($type = 0)
{
    if(Request::instance()
              ->header('authorization')){
        $token = Request::instance()->header('authorization');
        $type = substr($token ,0 ,7);
        if($type !== 'Bearer '){
            throw new \app\http\exception\UnauthorizedHttpException();
        }
        return  substr($token ,7);
    }
    //从协议头获取token
    return request()->param('token','');
}


/**
 * 替换字符串中间位置字符为星号
 *
 * @param  [type] $str [description]
 *
 * @return [type] [description]
 */
function replaceToStar($str)
{
    $len = strlen($str) / 2; //a0dca4d0****************ba444758]
    return substr_replace($str, str_repeat('*', $len), floor(($len) / 2), $len);
}

function abs_str($page, $limit)
{
    if (preg_match("/^[1-9][0-9]*$/", $page) && preg_match("/^[1-9][0-9]*$/", $page)) {
        return true;
    } else {
        return false;
    }
}

function access_token($appid, $secret)
{
    //获取微信accesstoken
    $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$secret";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $res = curl_exec($ch);
    //    var_dump($res);die;
    //    var_dump($res);die;
    //     var_dump($ch);die;
    curl_close($ch);
    $jsonArray = json_decode($res);
    //    var_dump($res);
    return $jsonArray;
    //    var_dump($jsonArray);
}

function get_client_ip()
{
    if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), 'unknown')) {
        $ip = getenv('HTTP_CLIENT_IP');
    } elseif (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), 'unknown')) {
        $ip = getenv('HTTP_X_FORWARDED_FOR');
    } elseif (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), 'unknown')) {
        $ip = getenv('REMOTE_ADDR');
    } elseif (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], 'unknown')) {
        $ip = $_SERVER['REMOTE_ADDR'];
    }
    return preg_match('/[\d\.]{7,15}/', $ip, $matches) ? $matches [0] : '';
}

function h5_access_token($id)
{
    //获取微信accesstoken
    $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=wxb7e13ea0208bc4c1&secret=b2b4a4085061d15241936c3114b6d9d6&code=$id&grant_type=authorization_code";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $res = curl_exec($ch);
    curl_close($ch);
    $jsonArray = json_decode($res);
    return $jsonArray;
    //    var_dump($jsonArray);
}

function get_latitude_longitude($address, $key)
{
    //获取微信accesstoken
    $url = "https://apis.map.qq.com/ws/geocoder/v1/?address=$address&key=$key";
    $addressInfo = json_decode(curl_send($url), true);
    return $addressInfo;
}

function sendRequest($method, $url, $requestBody = "")
{
    $ch = curl_init($url);
    if ($method == "1") {
        curl_setopt_array(
            $ch, [
                CURLOPT_HTTPGET        => true,
                CURLOPT_RETURNTRANSFER => true,
            ]
        );
    } elseif ($method == "2") {
        curl_setopt_array(
            $ch, [
                CURLOPT_POST           => true,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_SAFE_UPLOAD,
                false,
                CURLOPT_POSTFIELDS     => $requestBody

            ]
        );
    }
    // Send the request
    //    var_dump(curl_getinfo($ch));die;
    $response = curl_exec($ch);
    // Check for errors
    if ($response === false) {
        die(curl_error($ch));
    }

    return $response;
}

function uuid()
{
    $snowflake = new \Godruoyi\Snowflake\Snowflake;

    return $snowflake->id();
}

function snow_id(){
    return uuid();
}


function object2array($object)
{
    if (is_object($object)) {
        foreach ($object as $key => $value) {
            $array[$key] = $value;
        }
    } else {
        $array = $object;
    }
    return $array;
}

function curl_send($url)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $res = curl_exec($ch);
    curl_close($ch);
    return $res;
}

function getalphnum($char)
{
    $array = [
        'a',
        'b',
        'c',
        'd',
        'e',
        'f',
        'g',
        'h',
        'i',
        'j',
        'k',
        'l',
        'm',
        'n',
        'o',
        'p',
        'q',
        'r',
        's',
        't',
        'u',
        'v',
        'w',
        'x',
        'y',
        'z'
    ];
    $sum = 0;
    $len = strlen($char);
    for ($i = 0; $i < $len; $i++) {
        $index = array_search($char[$i], $array);
        $sum += ($index + 1) * pow(26, $len - $i - 1);
    }
    return $sum;
}

function postData($url, $postfields, $headers = [])
{
    $ch = curl_init();
    $params[CURLOPT_URL] = $url;            //请求url地址
    $params[CURLOPT_HEADER] = false;        //是否返回响应头信息
    $params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
    $params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
    $params[CURLOPT_POST] = true;
    $params[CURLOPT_POSTFIELDS] = $postfields;
    $params[CURLOPT_SSL_VERIFYPEER] = false;
    $params[CURLOPT_SSL_VERIFYHOST] = false;
    //以下是证书相关代码
    //            var_dump($params)
    curl_setopt_array($ch, $params);        //传入curl参数
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $content = curl_exec($ch); //执行
    //        var_dump(curl_error($ch));
    curl_close($ch);           //关闭连接
    return $content;
}


//获取剩余时间
function remainingTime($create_time)
{
    $current_time = time();

    if ($create_time > $current_time) {
        $dtCurrent = DateTime::createFromFormat('U', $current_time);
        $dtCreate = DateTime::createFromFormat('U', $create_time);
        $diff = $dtCurrent->diff($dtCreate);

        $interval = $diff->format("%d天%h小时");
        return preg_replace('/(^0| 0) (years|months|days|hours|minutes|seconds)/', '', $interval);
    }
    return '';
}

function identifyNoCreate($type = 1, $prefix = 'JD')
{
    $code = mt_rand(100, 999);
    $time = date('Ynd');
    return $prefix . $type . $time . $code;
}

function adminActionLog($menu_name, $msg, $userInfo = null, $explain = null)
{
    $json = [
        'menu_name' => $menu_name,
        'operation' => $msg ?? '-',
        'obj'       => json_encode($_REQUEST),
        'admin_ip'  => Visitor::getIP(),
        'explain'   => $explain ?? '-'
    ];
    AdminActionLog::build()
                  ->add($json, getAdmin());
}

/**
 * @param $value
 *
 * @return bool
 */
function parseBoolean($value)
{
    if (isset($value) == false) {
        return null;
    }

    if (is_bool($value)) {
        return $value;
    }

    if (is_string($value)) {
        $string = [
            'true'  => true,
            'false' => false,
            ''      => false,
            '1'     => true,
            '0'     => false
        ];

        if (in_array($value, $string) == false) {
            return true;
        }

        return $string[$value];
    }

    if (is_numeric($value)) {
        if ($value === 0) {
            return false;
        }
        return true;
    }

    return null;
}

//获取汉字的首字母
//function getFirstCharters($str)
//{
//    $str= mb_convert_encoding ( $str,"gb2312");//如果程序是gbk的，此行就要注释掉
//    if (preg_match("/^[\x7f-\xff]/", $str)) //判断是否全是中文
//    {
//        $fchar=ord($str{0});
//        if($fchar>=ord("A") and $fchar<=ord("z") )return strtoupper($str{0});
//        $a = $str;
//        $val=ord($a{0})*256+ord($a{1})-65536;
//        if($val>=-20319 and $val<=-20284)return "A";
//        if($val>=-20283 and $val<=-19776)return "B";
//        if($val>=-19775 and $val<=-19219)return "C";
//        if($val>=-19218 and $val<=-18711)return "D";
//        if($val>=-18710 and $val<=-18527)return "E";
//        if($val>=-18526 and $val<=-18240)return "F";
//        if($val>=-18239 and $val<=-17923)return "G";
//        if($val>=-17922 and $val<=-17418)return "H";
//        if($val>=-17417 and $val<=-16475)return "J";
//        if($val>=-16474 and $val<=-16213)return "K";
//        if($val>=-16212 and $val<=-15641)return "L";
//        if($val>=-15640 and $val<=-15166)return "M";
//        if($val>=-15165 and $val<=-14923)return "N";
//        if($val>=-14922 and $val<=-14915)return "O";
//        if($val>=-14914 and $val<=-14631)return "P";
//        if($val>=-14630 and $val<=-14150)return "Q";
//        if($val>=-14149 and $val<=-14091)return "R";
//        if($val>=-14090 and $val<=-13319)return "S";
//        if($val>=-13318 and $val<=-12839)return "T";
//        if($val>=-12838 and $val<=-12557)return "W";
//        if($val>=-12556 and $val<=-11848)return "X";
//        if($val>=-11847 and $val<=-11056)return "Y";
//        if($val>=-11055 and $val<=-10247)return "Z";
//    }
//    else
//    {
//        return false;
//    }
//}
//百家姓中的生僻字
function rare_words($asc = '')
{
    $rare_arr = [
        -3652  => ['word' => "窦", 'first_char' => 'D'],
        -8503  => ['word' => "奚", 'first_char' => 'X'],
        -9286  => ['word' => "酆", 'first_char' => 'F'],
        -7761  => ['word' => "岑", 'first_char' => 'C'],
        -5128  => ['word' => "滕", 'first_char' => 'T'],
        -9479  => ['word' => "邬", 'first_char' => 'W'],
        -5456  => ['word' => "臧", 'first_char' => 'Z'],
        -7223  => ['word' => "闵", 'first_char' => 'M'],
        -2877  => ['word' => "裘", 'first_char' => 'Q'],
        -6191  => ['word' => "缪", 'first_char' => 'M'],
        -5414  => ['word' => "贲", 'first_char' => 'B'],
        -4102  => ['word' => "嵇", 'first_char' => 'J'],
        -8969  => ['word' => "荀", 'first_char' => 'X'],
        -4938  => ['word' => "於", 'first_char' => 'Y'],
        -9017  => ['word' => "芮", 'first_char' => 'R'],
        -2848  => ['word' => "羿", 'first_char' => 'Y'],
        -9477  => ['word' => "邴", 'first_char' => 'B'],
        -9485  => ['word' => "隗", 'first_char' => 'K'],
        -6731  => ['word' => "宓", 'first_char' => 'M'],
        -9299  => ['word' => "郗", 'first_char' => 'X'],
        -5905  => ['word' => "栾", 'first_char' => 'L'],
        -4393  => ['word' => "钭", 'first_char' => 'T'],
        -9300  => ['word' => "郜", 'first_char' => 'G'],
        -8706  => ['word' => "蔺", 'first_char' => 'L'],
        -3613  => ['word' => "胥", 'first_char' => 'X'],
        -8777  => ['word' => "莘", 'first_char' => 'S'],
        -6708  => ['word' => "逄", 'first_char' => 'P'],
        -9302  => ['word' => "郦", 'first_char' => 'L'],
        -5965  => ['word' => "璩", 'first_char' => 'Q'],
        -6745  => ['word' => "濮", 'first_char' => 'P'],
        -4888  => ['word' => "扈", 'first_char' => 'H'],
        -9309  => ['word' => "郏", 'first_char' => 'J'],
        -5428  => ['word' => "晏", 'first_char' => 'Y'],
        -2849  => ['word' => "暨", 'first_char' => 'J'],
        -7206  => ['word' => "阙", 'first_char' => 'Q'],
        -4945  => ['word' => "殳", 'first_char' => 'S'],
        -9753  => ['word' => "夔", 'first_char' => 'K'],
        -10041 => ['word' => "厍", 'first_char' => 'S'],
        -5429  => ['word' => "晁", 'first_char' => 'C'],
        -2396  => ['word' => "訾", 'first_char' => 'Z'],
        -7205  => ['word' => "阚", 'first_char' => 'K'],
        -10049 => ['word' => "乜", 'first_char' => 'N'],
        -10015 => ['word' => "蒯", 'first_char' => 'K'],
        -3133  => ['word' => "竺", 'first_char' => 'Z'],
        -6698  => ['word' => "逯", 'first_char' => 'L'],
        -9799  => ['word' => "俟", 'first_char' => 'Q'],
        -6749  => ['word' => "澹", 'first_char' => 'T'],
        -7220  => ['word' => "闾", 'first_char' => 'L'],
        -10047 => ['word' => "亓", 'first_char' => 'Q'],
        -10005 => ['word' => "仉", 'first_char' => 'Z'],
        -3417  => ['word' => "颛", 'first_char' => 'Z'],
        -6431  => ['word' => "驷", 'first_char' => 'S'],
        -7226  => ['word' => "闫", 'first_char' => 'Y'],
        -9293  => ['word' => "鄢", 'first_char' => 'Y'],
        -6205  => ['word' => "缑", 'first_char' => 'G'],
        -9764  => ['word' => "佘", 'first_char' => 'S'],
        -9818  => ['word' => "佴", 'first_char' => 'N'],
        -9509  => ['word' => "谯", 'first_char' => 'Q'],
        -3122  => ['word' => "笪", 'first_char' => 'D'],
        -9823  => ['word' => "佟", 'first_char' => 'T'],
    ];
    if (array_key_exists($asc, $rare_arr) && $rare_arr[$asc]['first_char']) {
        return $rare_arr[$asc]['first_char'];
    } else {
        return null;
    }
}


/**
 * 获取数据库前缀
 *
 * @param string $table_name
 *
 * @return string
 */
function prefix(string $table_name = '') : string
{
    return strval(Config::get('database.prefix') . $table_name);
}


/**
 * 通过剩余的时间戳获取倒计时
 *
 * @param int $remain
 *
 * @return string
 */
function countdown(int $remain) : string
{
    $day = floor($remain / 60 / 60 / 24);

    $hour = floor(($remain % (60 * 60 * 24)) / 60 / 60);

    $min = floor((($remain % (60 * 60 * 24)) % (60 * 60)) / 60);

    return ($day > 0 ? $day . '天' : 0 . '天') . ($hour > 0 ? $hour . '时' : 0 . '时') . ($min > 0 ? $min . '分' : 0 . '分');
    // return ($day > 0 ?$day.'天':'').($hour>0 ?$hour.'时':'').($min>0 ?$min.'分':'');
    // return $day.'天' . $hour.'时' .  $min.'分';
}

/**
 * 时间范围转换时间戳数组
 *
 * @param string $dataRange
 *
 * @return array
 */
function dateRangeToTimestampArray(string $dataRange) : array
{
    if (strstr($dataRange, ' - ') == false) {
        return [];
    }

    $date = explode(' - ', $dataRange);

    $date[0] = strtotime($date[0]);
    $date[1] = strtotime($date[1]);

    return $date;
}

function getTime($url)
{
    //获取视频重定向后的链接
    $location = locationUrl($url);
    //获取视频Content-Length
    $responseHead = get_data($location);
    $list1 = explode("Content-Length: ", $responseHead);
    $list2 = explode("Connection", $list1[1]);
    $list = explode("x", $list2[0]);
    return $list[0];
}

//获取视频重定向后的链接
function locationUrl($url)
{
    $url_parts = @parse_url($url);
    if (!$url_parts) {
        return false;
    }
    if (!isset($url_parts['host'])) {
        return false;
    }
    if (!isset($url_parts['path'])) {
        $url_parts['path'] = '/';
    }
    $sock = fsockopen($url_parts['host'], (isset($url_parts['port']) ? (int)$url_parts['port'] : '80'), $errno, $errstr, 30);
    if (!$sock) {
        return false;
    }
    $request = "HEAD " . $url_parts['path'] . (isset($url_parts['query']) ? '?' . $url_parts['query'] : '') . " HTTP/1.1\r\n";
    $request .= 'Host: ' . $url_parts['host'] . "\r\n";
    $request .= "Connection: Close\r\n\r\n";
    fwrite($sock, $request);
    $response = '';
    while (!feof($sock)) {
        $response .= fread($sock, 8192);
    }
    fclose($sock);
    if (preg_match('/^Location: (.+?)$/m', $response, $matches)) {
        if (substr($matches[1], 0, 1) == "/") {
            return $url_parts['scheme'] . "://" . $url_parts['host'] . trim($matches[1]);
        } else {
            return trim($matches[1]);
        }
    } else {
        return false;
    }
}

//审核视频 curl
function get_data($url)
{
    $oCurl = curl_init();
    //模拟浏览器
    $header[] = "deo.com";
    $user_agent = "Mozilla/4.0 (Linux; Andro 6.0; Nexus 5 Build) AppleWeb/537.36 (KHTML, like Gecko)";
    curl_setopt($oCurl, CURLOPT_URL, $url);
    curl_setopt($oCurl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($oCurl, CURLOPT_HEADER, true);
    curl_setopt($oCurl, CURLOPT_NOBODY, true);
    curl_setopt($oCurl, CURLOPT_USERAGENT, $user_agent);
    curl_setopt($oCurl, CURLOPT_RETURNTRANSFER, 1);
    // 不用 POST 方式请求, 意思就是通过 GET 请求
    curl_setopt($oCurl, CURLOPT_POST, false);
    $sContent = curl_exec($oCurl);
    // 获得响应结果里的：头大小
    $headerSize = curl_getinfo($oCurl, CURLINFO_HEADER_SIZE);
    // 根据头大小去获取头信息内容
    $header = substr($sContent, 0, $headerSize);
    curl_close($oCurl);
    return $header;
}


// 验证身份证号
function checkIdCard($id_card)
{
    if (empty($id_card)) {
        return false;
    }
    $idcard = $id_card;
    $City = [
        11 => "北京",
        12 => "天津",
        13 => "河北",
        14 => "山西",
        15 => "内蒙古",
        21 => "辽宁",
        22 => "吉林",
        23 => "黑龙江",
        31 => "上海",
        32 => "江苏",
        33 => "浙江",
        34 => "安徽",
        35 => "福建",
        36 => "江西",
        37 => "山东",
        41 => "河南",
        42 => "湖北",
        43 => "湖南",
        44 => "广东",
        45 => "广西",
        46 => "海南",
        50 => "重庆",
        51 => "四川",
        52 => "贵州",
        53 => "云南",
        54 => "西藏",
        61 => "陕西",
        62 => "甘肃",
        63 => "青海",
        64 => "宁夏",
        65 => "新疆",
        71 => "台湾",
        81 => "香港",
        82 => "澳门",
        91 => "国外"
    ];
    $iSum = 0;
    $idCardLength = strlen($idcard);
    //长度验证
    if (!preg_match('/^\d{17}(\d|x)$/i', $idcard) and !preg_match('/^\d{15}$/i', $idcard)) {
        return '身份证不正确';
    }
    //地区验证
    if (!array_key_exists(intval(substr($idcard, 0, 2)), $City)) {
        return '身份证不正确';
    }
    // 15位身份证验证生日，转换为18位
    if ($idCardLength == 15) {
        $sBirthday = '19' . substr($idcard, 6, 2) . '-' . substr($idcard, 8, 2) . '-' . substr($idcard, 10, 2);
        //    $d = new DateTime($sBirthday);
        //    $dd = $d->format('Y-m-d');
        //    if($sBirthday != $dd)
        if ($sBirthday != $sBirthday) {
            return '身份证不正确';
        }
        $idcard = substr($idcard, 0, 6) . "19" . substr($idcard, 6, 9);//15to18
        $Bit18 = getVerifyBit($idcard);                                //算出第18位校验码
        $idcard = $idcard . $Bit18;
    }
    // 判断是否大于2078年，小于1900年
    $year = substr($idcard, 6, 4);
    if ($year < 1900 || $year > 2078) {
        return '身份证不正确';
    }

    //18位身份证处理
    $sBirthday = substr($idcard, 6, 4) . '-' . substr($idcard, 10, 2) . '-' . substr($idcard, 12, 2);
    //    var_dump($sBirthday);
    //    $d = new DateTime($sBirthday);

    //    $dd = $d->format('Y-m-d');
    //    echo $dd;
    //    die();
    //    if($sBirthday != $dd)
    if ($sBirthday != $sBirthday) {
        return '身份证不正确';
    }
    //身份证编码规范验证
    $idcard_base = substr($idcard, 0, 17);
    if (strtoupper(substr($idcard, 17, 1)) != getVerifyBit($idcard_base)) {
        return '身份证不正确';
    }
    return true;
}

// 计算身份证校验码，根据国家标准GB 11643-1999
function getVerifyBit($idcard_base)
{
    if (strlen($idcard_base) != 17) {
        return '身份证不正确';
    }
    //加权因子
    $factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
    //校验码对应值
    $verify_number_list = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
    $checksum = 0;
    for ($i = 0; $i < strlen($idcard_base); $i++) {
        $checksum += substr($idcard_base, $i, 1) * $factor[$i];
    }
    $mod = $checksum % 11;
    $verify_number = $verify_number_list[$mod];
    return $verify_number;
}

// 校验银行卡是否正确
function checkBankNo($bankNo)
{
    $api_url = "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?cardNo={$bankNo}&cardBinCheck=true";
    $res = file_get_contents($api_url);
    $bankCard = json_decode($res, true);
    $bank = [
        "CDB"       => "国家开发银行",
        "ICBC"      => "中国工商银行",
        "ABC"       => "中国农业银行",
        "BOC"       => "中国银行",
        "CCB"       => "中国建设银行",
        "PSBC"      => "中国邮政储蓄银行",
        "COMM"      => "交通银行",
        "CMB"       => "招商银行",
        "SPDB"      => "上海浦东发展银行",
        "CIB"       => "兴业银行",
        "HXBANK"    => "华夏银行",
        "GDB"       => "广东发展银行",
        "CMBC"      => "中国民生银行",
        "CITIC"     => "中信银行",
        "CEB"       => "中国光大银行",
        "EGBANK"    => "恒丰银行",
        "CZBANK"    => "浙商银行",
        "BOHAIB"    => "渤海银行",
        "SPABANK"   => "平安银行",
        "SHRCB"     => "上海农村商业银行",
        "YXCCB"     => "玉溪市商业银行",
        "YDRCB"     => "尧都农商行",
        "BJBANK"    => "北京银行",
        "SHBANK"    => "上海银行",
        "JSBANK"    => "江苏银行",
        "HZCB"      => "杭州银行",
        "NJCB"      => "南京银行",
        "NBBANK"    => "宁波银行",
        "HSBANK"    => "徽商银行",
        "CSCB"      => "长沙银行",
        "CDCB"      => "成都银行",
        "CQBANK"    => "重庆银行",
        "DLB"       => "大连银行",
        "NCB"       => "南昌银行",
        "FJHXBC"    => "福建海峡银行",
        "HKB"       => "汉口银行",
        "WZCB"      => "温州银行",
        "QDCCB"     => "青岛银行",
        "TZCB"      => "台州银行",
        "JXBANK"    => "嘉兴银行",
        "CSRCB"     => "常熟农村商业银行",
        "NHB"       => "南海农村信用联社",
        "CZRCB"     => "常州农村信用联社",
        "H3CB"      => "内蒙古银行",
        "SXCB"      => "绍兴银行",
        "SDEB"      => "顺德农商银行",
        "WJRCB"     => "吴江农商银行",
        "ZBCB"      => "齐商银行",
        "GYCB"      => "贵阳市商业银行",
        "ZYCBANK"   => "遵义市商业银行",
        "HZCCB"     => "湖州市商业银行",
        "DAQINGB"   => "龙江银行",
        "JINCHB"    => "晋城银行JCBANK",
        "ZJTLCB"    => "浙江泰隆商业银行",
        "GDRCC"     => "广东省农村信用社联合社",
        "DRCBCL"    => "东莞农村商业银行",
        "MTBANK"    => "浙江民泰商业银行",
        "GCB"       => "广州银行",
        "LYCB"      => "辽阳市商业银行",
        "JSRCU"     => "江苏省农村信用联合社",
        "LANGFB"    => "廊坊银行",
        "CZCB"      => "浙江稠州商业银行",
        "DYCB"      => "德阳商业银行",
        "JZBANK"    => "晋中市商业银行",
        "BOSZ"      => "苏州银行",
        "GLBANK"    => "桂林银行",
        "URMQCCB"   => "乌鲁木齐市商业银行",
        "CDRCB"     => "成都农商银行",
        "ZRCBANK"   => "张家港农村商业银行",
        "BOD"       => "东莞银行",
        "LSBANK"    => "莱商银行",
        "BJRCB"     => "北京农村商业银行",
        "TRCB"      => "天津农商银行",
        "SRBANK"    => "上饶银行",
        "FDB"       => "富滇银行",
        "CRCBANK"   => "重庆农村商业银行",
        "ASCB"      => "鞍山银行",
        "NXBANK"    => "宁夏银行",
        "BHB"       => "河北银行",
        "HRXJB"     => "华融湘江银行",
        "ZGCCB"     => "自贡市商业银行",
        "YNRCC"     => "云南省农村信用社",
        "JLBANK"    => "吉林银行",
        "DYCCB"     => "东营市商业银行",
        "KLB"       => "昆仑银行",
        "ORBANK"    => "鄂尔多斯银行",
        "XTB"       => "邢台银行",
        "JSB"       => "晋商银行",
        "TCCB"      => "天津银行",
        "BOYK"      => "营口银行",
        "JLRCU"     => "吉林农信",
        "SDRCU"     => "山东农信",
        "XABANK"    => "西安银行",
        "HBRCU"     => "河北省农村信用社",
        "NXRCU"     => "宁夏黄河农村商业银行",
        "GZRCU"     => "贵州省农村信用社",
        "FXCB"      => "阜新银行",
        "HBHSBANK"  => "湖北银行黄石分行",
        "ZJNX"      => "浙江省农村信用社联合社",
        "XXBANK"    => "新乡银行",
        "HBYCBANK"  => "湖北银行宜昌分行",
        "LSCCB"     => "乐山市商业银行",
        "TCRCB"     => "江苏太仓农村商业银行",
        "BZMD"      => "驻马店银行",
        "GZB"       => "赣州银行",
        "WRCB"      => "无锡农村商业银行",
        "BGB"       => "广西北部湾银行",
        "GRCB"      => "广州农商银行",
        "JRCB"      => "江苏江阴农村商业银行",
        "BOP"       => "平顶山银行",
        "TACCB"     => "泰安市商业银行",
        "CGNB"      => "南充市商业银行",
        "CCQTGB"    => "重庆三峡银行",
        "XLBANK"    => "中山小榄村镇银行",
        "HDBANK"    => "邯郸银行",
        "KORLABANK" => "库尔勒市商业银行",
        "BOJZ"      => "锦州银行",
        "QLBANK"    => "齐鲁银行",
        "BOQH"      => "青海银行",
        "YQCCB"     => "阳泉银行",
        "SJBANK"    => "盛京银行",
        "FSCB"      => "抚顺银行",
        "ZZBANK"    => "郑州银行",
        "SRCB"      => "深圳农村商业银行",
        "BANKWF"    => "潍坊银行",
        "JJBANK"    => "九江银行",
        "JXRCU"     => "江西省农村信用",
        "HNRCU"     => "河南省农村信用",
        "GSRCU"     => "甘肃省农村信用",
        "SCRCU"     => "四川省农村信用",
        "GXRCU"     => "广西省农村信用",
        "SXRCCU"    => "陕西信合",
        "WHRCB"     => "武汉农村商业银行",
        "YBCCB"     => "宜宾市商业银行",
        "KSRB"      => "昆山农村商业银行",
        "SZSBK"     => "石嘴山银行",
        "HSBK"      => "衡水银行",
        "XYBANK"    => "信阳银行",
        "NBYZ"      => "鄞州银行",
        "ZJKCCB"    => "张家口市商业银行",
        "XCYH"      => "许昌银行",
        "JNBANK"    => "济宁银行",
        "CBKF"      => "开封市商业银行",
        "WHCCB"     => "威海市商业银行",
        "HBC"       => "湖北银行",
        "BOCD"      => "承德银行",
        "BODD"      => "丹东银行",
        "JHBANK"    => "金华银行",
        "BOCY"      => "朝阳银行",
        "LSBC"      => "临商银行",
        "BSB"       => "包商银行",
        "LZYH"      => "兰州银行",
        "BOZK"      => "周口银行",
        "DZBANK"    => "德州银行",
        "SCCB"      => "三门峡银行",
        "AYCB"      => "安阳银行",
        "ARCU"      => "安徽省农村信用社",
        "HURCB"     => "湖北省农村信用社",
        "HNRCC"     => "湖南省农村信用社",
        "NYNB"      => "广东南粤银行",
        "LYBANK"    => "洛阳银行",
        "NHQS"      => "农信银清算中心",
        "CBBQS"     => "城市商业银行资金清算中心"
    ];
    if (!$bankCard['validated']) {
        return ['check' => false, 'bank_name' => ''];
    }
    $bank_name = $bank[$bankCard['bank']];
    return ['check' => true, 'bank_name' => $bank_name];
}

/**
 * 返回阿里云oss资源的完整地址
 *
 * @param string $key
 *
 * @return string
 */
function oss_url(string $key)
{
    $config = Config::get('alioss');

    return $config['url'] . $key;
}

/**
 * 获取平台im账号
 */
function getPlatformImUsername() : string
{
    $value = \app\api\model\Config::where('label', 'service_im_username')
                                  ->value('value');

    return strval($value);
}


function getLocation(string $address)
{
    $ak = 'jd2EYPH4uTp6Pij4rhArQSO24y41jLMn';

    $url = 'http://api.map.baidu.com/geocoding/v3/?address=' . $address . '&output=json&ak=' . $ak . '&callback=showLocation';
    $result = file_get_contents($url);

    $result = json_decode(substr($result, strpos($result, '{'), strrpos($result, ')') - strlen($result)), true);

    if ($result['status'] == 1) {
        throw new \think\exception\HttpException(400, '邮寄地址输入有误');
    }
    return $result['result']['location'];
}

/**
 * 验证姓名及身份证是否一致
 *
 * @param $name
 * @param $id
 */
function verifyIdCard($name, $id)
{
    $url = "https://eid.shumaidata.com/eid/check";
    $appcode = "dd215ae3a7ed400fa6acc09f2629d449";
    $headers = [];
    array_push($headers, "Authorization:APPCODE " . $appcode);

    $result = postData($url, ['idcard' => $id, 'name' => $name], $headers);
    $result = json_decode($result, true);
    if ($result['code'] != 0) {
        return ['msg' => $result['message']];
    }
    if ($result['code'] == 0 && $result['result']['res'] != 1) {
        return ['msg' => '身份证号不一致'];
    }
    return true;
}

function diffBetweenTwoDays($day1, $day2)
{
    $second1 = strtotime(date('Y-m-d', strtotime($day1)));
    $second2 = strtotime(date('Y-m-d', strtotime($day2)));

    if ($second1 < $second2) {
        $tmp = $second2;
        $second2 = $second1;
        $second1 = $tmp;
    }
    return ceil(($second1 - $second2) / 86400);
}


function set_globals($user_uuid, $user)
{
    $GLOBALS['client'] = [
        'user_uuid' => $user_uuid,
        'user'      => $user,
    ];
}

function set_admin_global($admin_uuid, $admin)
{
    $GLOBALS['admin'] = [
        'admin_uuid' => $admin_uuid,
        'admin'      => $admin
    ];
}


function get_admin_uuid()
{
    return $GLOBALS['admin']['admin_uuid'];
}

function get_admin()
{
    return $GLOBALS['admin']['admin'];
}


function get_client_id()
{
    return $GLOBALS['client']['client_id'] ?? 0;
}

function is_client() : bool
{
    return strtoupper(get_client_type()) == APP;
}

function get_group_id()
{
    return $GLOBALS['client']['group_id'] ?? 0;
}

function get_client_name()
{
    return $GLOBALS['client']['client_name'] ?? 'system';
}


function get_client_type()
{
    return $GLOBALS['client']['type'] ?? 'admin';
}


function get_user()
{
    return $GLOBALS['client']['user'];
}


function get_setting($key)
{
    $info = \app\common\model\Setting::build()
                                     ->where('key', $key)
                                     ->find();
    if(!$info){
        error_abort(sprintf('%s 配置不存在' ,$key));
    }
    return $info['value'];
}


/**
 * @return int $age
 */
function get_age($date)
{
    #  获得出生年月日的时间戳
    #  获得今日的时间戳
    $today = strtotime('today');
    #  得到两个日期相差的大体年数
    $diff = floor(($today - strtotime($date)) / 86400 / 365);
    #  strtotime加上这个年数后得到那日的时间戳后与今日的时间戳相比
    $age = strtotime($date . ' +' . $diff . 'years') > $today ? ($diff + 1) : $diff;
    return $age;
}


# EXCEL导出
function excel_export($result, $field, $file = 'xx')
{
    $column = [
        'A',
        'B',
        'C',
        'D',
        'E',
        'F',
        'G',
        'H',
        'I',
        'J',
        'K',
        'L',
        'M',
        'N',
        'O',
        'P',
        'Q',
        'R',
        'S',
        'T',
        'U',
        'V',
        'W',
        'X',
        'Y',
        'Z',
        'AA',
        'AB',
        'AC',
        'AD',
        'AE',
        'AF',
        'AG',
        'AH'
    ];

    $objPHPExcel = new \PHPExcel();
    $filedIndex = 0;
    foreach ($field as $k => $v) {
        $objPHPExcel->getActiveSheet()
                    ->setCellValue(sprintf('%s%u', $column[$filedIndex], '1'), $v);
        $filedIndex++;
    }

    //循环设置行
    $num = 1;
    foreach ($result as $vv) {
        $num += 1;
        $cell = $objPHPExcel->setActiveSheetIndex(0);
        $index = 0;
        foreach ($field as $kkk => $vvv) {
            $keys = explode('.', $kkk);
            if (count($keys) == 1) {
                $cell->setCellValue(sprintf('%s%u', $column[$index], $num), removeEmoji($vv[$kkk]) . "\t");
            } elseif (count($keys) == 2) {
                $cell->setCellValue(sprintf('%s%u', $column[$index], $num), removeEmoji($vv[$keys[0]][$keys[1]]) . "\t");
            }

            $index++;
        }
    }
    //设置单元格字体
    $objPHPExcel->getDefaultStyle()
                ->getAlignment()
                ->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
    $objPHPExcel->getActiveSheet()
                ->setTitle('User');
    $objPHPExcel->setActiveSheetIndex(0);
    header('Content-Type: applicationnd.ms-excel');
    $filename = $file . '-' . date("Ymd");

    header("Content-Disposition: attachment;filename={$filename}.xls");
    header('Cache-Control: max-age=0');

    $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
    // return ajax('成功');
    $objWriter->save('php://output');
}

function get_name_by_status($filed, $value)
{
    if (is_null($value)) {
        return '';
    }
    $key = sprintf('dict:%s:%s', $filed, $value);
    $label = cache($key);
    if (!$label) {
        $label = \app\common\model\Dict::build()
                                       ->where('field_name', $filed)
                                       ->where('value', $value)
                                       ->value('label');
        $label && cache($key, $label, 3600);
    }
    return $label;
}


function m_abort(string $message, int $code = 402, $data = [])
{
    abort($code, $message);
    //    throw new \app\api\exception\ApiException($message ,$code );
}

function business_abort(int $code = 402, string $message = '', $data = [])
{
    throw new BusinessException($message, $code);
}

function error_abort(string $message, int $code = 402, $data = [])
{
    abort($code, $message);
    //    throw new \app\api\exception\ApiException($message ,$code ,$data);
}


function removeEmoji($str)
{
    $str = preg_replace_callback(
        '/./u',
        function (array $match)
        {
            return strlen($match[0]) >= 4 ? '' : $match[0];
        }, $str
    );
    return $str;
}


/**
 * @name       : get_encoding
 * @description: 自动检测内容编码进行转换
 *
 * @param      : string data
 * @param      : string to  目标编码
 *
 * @return     : string
 **/
function get_encoding($data, $to)
{
    $encode_arr = ['UTF-8', 'ASCII', 'GBK', 'GB2312', 'BIG5', 'JIS', 'eucjp-win', 'sjis-win', 'EUC-JP'];
    $encoded = mb_detect_encoding($data, $encode_arr);
    $data = mb_convert_encoding($data, $to, $encoded);
    return $data;
}


/**
 * 解析json串
 */
function getJson($json_str)
{
    $json_str = str_replace('＼＼', '', $json_str);
    $out_arr = [];
    preg_match('/{.*}/', $json_str, $out_arr);
    if (!empty($out_arr)) {
        $result = json_decode($out_arr[0], true);
    } else {
        return false;
    }
    return $result;
}


if (!function_exists('get_ip2region_str')) {
    /**
     * 将Ip2Region查询到的IP进行格式化
     *
     * @param string $ip IP地址
     *
     * @return string
     */
    function get_ip2region_str(string $ip)
    {
        $ipStr = '';
        [
            $country,
            ,
            $region,
            $city,
            $isp
        ] = explode('|', $ip);

        '0' === $country ?: $ipStr .= $country;
        '0' === $region ?: $ipStr .= $region;
        '0' === $city ?: $ipStr .= $city;
        '0' === $isp ?: $ipStr .= " {$isp}";

        return trim($ipStr);
    }
}

if (!function_exists('get_client_group')) {
    /**
     * 返回当前账号用户组编号
     *
     * @return int
     */
    function get_client_group()
    {
        return isset($GLOBALS['client']['group_id']) ? $GLOBALS['client']['group_id'] : AUTH_GUEST;
    }
}

if (!function_exists('is_empty_parm')) {
    /**
     * 判断是否为空参数
     *
     * @param mixed $parm
     *
     * @return bool
     */
    function is_empty_parm(&$parm)
    {
        return !(isset($parm) && '' !== $parm);
    }
}

//获取自增序列
function getSequence($name)
{
    //    dd(getSequence('staff_no'));
    $key = 'sequence-lock:' . $name;
    $lock = RedisLock::getInstance(MyRedis::getInstance('cache.stores.redis'));
    $value = 0;
    $lock->run(function () use ($name, &$value)
    {
        $result = \think\facade\Db::query("SELECT NEXTVAL('{$name}')");
        $value = array_values($result[0])[0];
    }, $key);

    return $value;

    //    INSERT INTO sequence VALUES ('staff_no', 0, 1)
    //SELECT SETVAL('staff_no', 10);--设置指定sequence的初始值
    //
    //SELECT CURRVAL('staff_no');--查询指定sequence的当前值
    //
    //SELECT NEXTVAL('staff_no');--查询指定sequence的下一个值
}

function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0)
{
    if ($operation === 'DECODE') {
        $string = base64_decode($string);
        [$str, $sign] = explode('||||', $string);
        if ($sign === md6($str . $key)) {
            return $str;
        } else {
            error_abort('数据非法,解密异常');
        }
    } else {
        $str = $string . '||||' . md6($string . $key);
        return base64_encode($str);
    }
}


function get_stores()
{
    return $GLOBALS['client']['stores'] ?? 'ALL';
}

function set_menu($menu = '')
{
    return $GLOBALS['menu'] = $menu;
}

function get_menu()
{
    return $GLOBALS['menu']??'-';
}